from selenium.webdriver.edge.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.common.by import By
from .module_finder_near_input import (find_element_smart, by_text_find_element, by_text_find_inputUpload_Element,
                                      by_text_find_inputUploadImage_Element, by_text_find_input_element, by_text_find_inputUploadVideo_Element)
import datetime
import typing


class FinderElementBase:
    def __init__(self, driver: WebDriver):
        self.driver: WebDriver = driver

    def find_element(self, xpath) -> WebElement:
        return self.driver.find_element(by=By.XPATH, value=xpath)

    def find_element_safe(self, xpath, timeout=10) -> WebElement:
        _startTime = datetime.datetime.now()
        _seconds = timeout
        _element: WebElement = None
        _elementXpathValue = xpath
        while _startTime + datetime.timedelta(seconds=_seconds) > datetime.datetime.now():
            try:
                _element = self.driver.find_element(
                    by=By.XPATH, value=_elementXpathValue)
                break
            except:
                continue
        return _element

    def verify_element(self, xpath, timeout=5) -> bool:
        return True if self.find_element_safe(xpath=xpath, timeout=timeout) else False

    def wait_element(self,xpath,timeout=5) -> bool:
        return self.verify_element(xpath=xpath,timeout=timeout)

    def find_element_with_condition(self, xpath, condition_xpath: str = None, timeout=10) -> WebElement | None:
        if condition_xpath is None:
            return self.find_element_safe(xpath=xpath, timeout=timeout)
        else:
            if self.verify_element(xpath=condition_xpath,timeout=timeout):
                return self.find_element_safe(xpath=xpath, timeout=timeout)
            else:
                return None

    def find_element_smart(self, source_element: typing.Union[WebElement, str, None], target_xpath: str, max_parent_levels: int = 5) -> typing.Optional[WebElement]:
        element = find_element_smart(driver=self.driver,
                                     source_element=source_element,
                                     target_xpath=target_xpath,
                                     max_parent_levels=max_parent_levels)
        return element

    def by_text_find_element(self, text: str, text_type: typing.Literal["equal", "contains"], target_xpath: str, max_parent_levels: int = 5) -> typing.Optional[WebElement]:
        element = by_text_find_element(driver=self.driver,
                                       text=text,
                                       text_type=text_type,
                                       target_xpath=target_xpath,
                                       max_parent_levels=max_parent_levels
                                       )
        return element

    def by_text_find_input_element(self, text: str, text_type: typing.Literal["equal", "contains"], target_xpath: str, max_parent_levels: int = 5) -> typing.Optional[WebElement]:
        element = by_text_find_input_element(driver=self.driver,
                                             text=text,
                                             text_type=text_type,
                                             target_xpath=target_xpath,
                                             max_parent_levels=max_parent_levels
                                             )
        return element

    def by_text_find_inputUpload_Element(self, text: str, text_type: typing.Literal["equal", "contains"], target_xpath: str = "input[@type='file']", max_parent_levels: int = 5) -> typing.Optional[WebElement]:
        element = by_text_find_inputUpload_Element(driver=self.driver,
                                                   text=text,
                                                   text_type=text_type,
                                                   target_xpath=target_xpath,
                                                   max_parent_levels=max_parent_levels
                                                   )
        return element

    def by_text_find_inputUploadImage_Element(self, text: str, text_type: typing.Literal["equal", "contains"], target_xpath: str = "input[@type='file'][contains(@accept,'image')]", max_parent_levels: int = 5) -> typing.Optional[WebElement]:
        element = by_text_find_inputUploadImage_Element(driver=self.driver,
                                                        text=text,
                                                        text_type=text_type,
                                                        target_xpath=target_xpath,
                                                        max_parent_levels=max_parent_levels
                                                        )
        return element

    def by_text_find_inputUploadVideo_Element(self, text: str, text_type: typing.Literal["equal", "contains"], target_xpath: str = "input[@type='file'][contains(@accept,'video')]", max_parent_levels: int = 5) -> typing.Optional[WebElement]:
        element = by_text_find_inputUploadVideo_Element(driver=self.driver,
                                                        text=text,
                                                        text_type=text_type,
                                                        target_xpath=target_xpath,
                                                        max_parent_levels=max_parent_levels
                                                        )
        return element
